﻿// Decompiled with JetBrains decompiler
// Type: Netick.BitBuffer
// Assembly: Netick, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null
// MVID: 6726ECA1-C773-4CF7-8952-E81B30D93B52
// Assembly location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.dll
// XML documentation location: D:\WorkSpaceDemo\UPM\NetickForUnity\Netick\Runtime\Netick.xml

using System;
using System.Runtime.CompilerServices;

#nullable disable
namespace Netick;

public sealed class BitBuffer
{
  private const int DefaultCapacity = 875;
  public int ReadPosition;
  public int WritePos;
  internal unsafe uint* _chunks;
  internal unsafe uint* _chunksOriginal;
  internal unsafe byte* _chunksByte;
  internal IntPtr _chunksPtr;
  private bool _createChunks;
  internal int _len;
  internal int writtenByteSize;

  public unsafe BitBuffer(int capacity = 875, bool createChunks = true)
  {
    this._len = capacity;
    this._createChunks = createChunks;
    this.ReadPosition = 0;
    this.WritePos = 0;
    if (!createChunks)
      return;
    this._chunks = (uint*) MemoryAllocation.Malloc((long) (capacity * 4), sizeof (IntPtr));
    this._chunksOriginal = this._chunks;
    this._chunksPtr = new IntPtr((void*) this._chunks);
    this._chunksByte = (byte*) this._chunks;
  }

  unsafe ~BitBuffer()
  {
    if (!this._createChunks)
      return;
    MemoryAllocation.Free((void*) this._chunksOriginal);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public unsafe void SetFrom(byte* source, int len, int bufferSize)
  {
    int highestBitPosition = BitBuffer.FindHighestBitPosition(source[len - 1]);
    this.WritePos = (len - 1) * 8 + (highestBitPosition - 1);
    this.ReadPosition = 0;
    this._len = bufferSize / 4;
    this.writtenByteSize = len;
    this._chunks = (uint*) source;
    this._chunksPtr = new IntPtr((void*) this._chunks);
    this._chunksByte = (byte*) this._chunks;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public int Length() => (this.WritePos - 1 >> 3) + 1;

  public bool IsFinished => this.WritePos == this.ReadPosition;

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public void Clear()
  {
    this.ReadPosition = 0;
    this.WritePos = 0;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public unsafe void Add(int numBits, uint value)
  {
    int index = this.WritePos >> 5;
    int num1 = this.WritePos & 31 /*0x1F*/;
    ulong num2 = (ulong) ((long) this._chunks[index] & (1L << num1) - 1L | (long) value << num1);
    this._chunks[index] = (uint) num2;
    this._chunks[index + 1] = (uint) (num2 >> 32 /*0x20*/);
    this.WritePos += numBits;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public unsafe void Insert(int position, int numBits, uint value)
  {
    int index = position >> 5;
    int num1 = position & 31 /*0x1F*/;
    ulong num2 = (ulong) (1L << numBits) - 1UL;
    ulong num3 = (ulong) (((long) value & (long) num2) << num1);
    ulong num4 = (ulong) this._chunks[index] | (ulong) this._chunks[index + 1] << 32 /*0x20*/ | num3;
    this._chunks[index] = (uint) num4;
    this._chunks[index + 1] = (uint) (num4 >> 32 /*0x20*/);
  }

  public void AlignWritePosToByte()
  {
    int num = this.WritePos % 8;
    if (num == 0)
      return;
    this.Add(8 - num, 0U);
  }

  public void AlignReadPosToByte()
  {
    int num1 = this.ReadPosition % 8;
    if (num1 == 0)
      return;
    int num2 = (int) this.Read(8 - num1);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public uint Read(int numBits)
  {
    int num = (int) this.Peek(numBits);
    this.ReadPosition += numBits;
    return (uint) num;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public unsafe uint Peek(int numBits)
  {
    int index = this.ReadPosition >> 5;
    int num1 = this.ReadPosition & 31 /*0x1F*/;
    ulong num2 = (ulong) ((1L << numBits) - 1L << num1);
    return (uint) ((((ulong) this._chunks[index] | (ulong) this._chunks[index + 1] << 32 /*0x20*/) & num2) >> num1);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public void AddInt(int value) => this.AddUInt((uint) (value << 1 ^ value >> 31 /*0x1F*/));

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public int ReadInt()
  {
    uint num = this.ReadUInt();
    return (int) ((long) (num >> 1) ^ (long) -((int) num & 1));
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public int PeekInt()
  {
    uint num = this.PeekUInt();
    return (int) ((long) (num >> 1) ^ (long) -((int) num & 1));
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public void FlexAddUInt(uint value, uint x1, uint x2, int stepSize)
  {
    do
    {
      uint num = value & x1;
      value >>= stepSize - 1;
      if (value > 0U)
        num |= x2;
      this.Add(stepSize, num);
    }
    while (value > 0U);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public uint FlexReadUInt_(uint x1, uint x2, int stepSize)
  {
    uint num1 = 0;
    int num2 = 0;
    uint num3;
    do
    {
      num3 = this.Read(stepSize);
      num1 |= (uint) (((int) num3 & (int) x1) << num2);
      num2 += stepSize - 1;
    }
    while ((num3 & x2) > 0U);
    return num1;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public void AddInt4(int value) => this.AddUInt4((uint) (value << 1 ^ value >> 31 /*0x1F*/));

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public int ReadInt4()
  {
    uint num = this.ReadUInt4();
    return (int) ((long) (num >> 1) ^ (long) -((int) num & 1));
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public void AddUInt4(uint value)
  {
    do
    {
      uint num = value & 7U;
      value >>= 3;
      if (value > 0U)
        num |= 8U;
      this.Add(4, num);
    }
    while (value > 0U);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public uint ReadUInt4()
  {
    uint num1 = 0;
    int num2 = 0;
    uint num3;
    do
    {
      num3 = this.Read(4);
      num1 |= (uint) (((int) num3 & 7) << num2);
      num2 += 3;
    }
    while ((num3 & 8U) > 0U);
    return num1;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public void AddInt2(int value) => this.AddUInt2((uint) (value << 1 ^ value >> 31 /*0x1F*/));

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public int ReadInt2()
  {
    uint num = this.ReadUInt2();
    return (int) ((long) (num >> 1) ^ (long) -((int) num & 1));
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public void AddUInt2(uint value)
  {
    do
    {
      uint num = value & 1U;
      value >>= 1;
      if (value > 0U)
        num |= 2U;
      this.Add(2, num);
    }
    while (value > 0U);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public uint ReadUInt2()
  {
    uint num1 = 0;
    int num2 = 0;
    uint num3;
    do
    {
      num3 = this.Read(2);
      num1 |= (uint) (((int) num3 & 1) << num2);
      ++num2;
    }
    while ((num3 & 2U) > 0U);
    return num1;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public void AddUInt(uint value)
  {
    do
    {
      uint num = value & (uint) sbyte.MaxValue;
      value >>= 7;
      if (value > 0U)
        num |= 128U /*0x80*/;
      this.Add(8, num);
    }
    while (value > 0U);
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public uint ReadUInt()
  {
    uint num1 = 0;
    int num2 = 0;
    uint num3;
    do
    {
      num3 = this.Read(8);
      num1 |= (uint) (((int) num3 & (int) sbyte.MaxValue) << num2);
      num2 += 7;
    }
    while ((num3 & 128U /*0x80*/) > 0U);
    return num1;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public uint PeekUInt()
  {
    int readPosition = this.ReadPosition;
    int num = (int) this.ReadUInt();
    this.ReadPosition = readPosition;
    return (uint) num;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public BitBuffer AddLong(long value)
  {
    this.AddInt((int) (value & (long) uint.MaxValue));
    this.AddInt((int) (value >> 32 /*0x20*/));
    return this;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public long ReadLong()
  {
    int num = this.ReadInt();
    return (long) this.ReadInt() << 32 /*0x20*/ | (long) (uint) num;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public long PeekLong()
  {
    int readPosition = this.ReadPosition;
    long num = this.ReadLong();
    this.ReadPosition = readPosition;
    return num;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public BitBuffer AddULong(ulong value)
  {
    this.AddUInt((uint) (value & (ulong) uint.MaxValue));
    this.AddUInt((uint) (value >> 32 /*0x20*/));
    return this;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public ulong ReadULong()
  {
    uint num = this.ReadUInt();
    return (ulong) this.ReadUInt() << 32 /*0x20*/ | (ulong) num;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public ulong PeekULong()
  {
    int readPosition = this.ReadPosition;
    long num = (long) this.ReadULong();
    this.ReadPosition = readPosition;
    return (ulong) num;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  internal static int FindHighestBitPosition(byte data)
  {
    int highestBitPosition = 0;
    while (data > (byte) 0)
    {
      data >>= 1;
      ++highestBitPosition;
    }
    return highestBitPosition;
  }

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public void AddBool(bool value) => this.Add(1, value ? 1U : 0U);

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public bool ReadBool() => this.Read(1) > 0U;

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public bool PeekBool() => this.Peek(1) > 0U;

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public void AddByte(byte value) => this.Add(8, (uint) value);

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public byte ReadByte() => (byte) this.Read(8);

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  public byte PeekByte() => (byte) this.Peek(8);

  [MethodImpl(MethodImplOptions.AggressiveInlining)]
  internal Tick ReadTick() => new Tick(this.ReadInt());
}
